<template>
  <div class="app-container">
    <div class="search-bar">
      <el-form ref="queryFormRef" :model="queryParams" :inline="true">
        <el-form-item prop="keywords" :label="$t('common.keywords')">
          <el-input
            v-model="queryParams.keywords"
            :placeholder="$t('device.queryKeywords')"
            clearable
            @keyup.enter="handleQuery"
          />
        </el-form-item>
        <el-form-item prop="deviceType" :label="$t('device.deviceType.title')">
          <el-select
            v-model="queryParams.deviceType"
            :placeholder="$t('common.choose')"
            :no-match-text="$t('common.choose')"
            style="width: 300px"
            @change="handleQuery"
          >
            <el-option
              v-for="item in deviceTypeOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" icon="search" @click="handleQuery">
            {{ $t("common.search") }}
          </el-button>
          <el-button icon="refresh" @click="handleResetQuery">{{ $t("common.reset") }}</el-button>
        </el-form-item>
      </el-form>
    </div>

    <el-card shadow="never">
      <div class="mb-10px">
        <el-button v-hasPerm="'device:add'" icon="Refresh" @click="refreshGateway" />
        <el-button
          v-hasPerm="'device:add'"
          :loading="scanBluetooth"
          type="primary"
          @click="connectAndRead"
        >
          {{ gatewayBtnTitle }}
        </el-button>
        <el-button v-hasPerm="'device:add'" type="success" icon="plus" @click="handleOpenDialog()">
          {{ $t("common.add") + $t("device.deviceType.node") }}
        </el-button>
        <el-button
          v-hasPerm="'device:delete'"
          type="danger"
          :disabled="ids.length === 0"
          icon="delete"
          @click="handleDelete()"
        >
          {{ $t("common.delete") }}
        </el-button>
      </div>

      <el-table
        ref="dataTableRef"
        v-loading="loading"
        stripe
        :data="list"
        highlight-current-row
        @selection-change="handleSelectionChange"
      >
        <el-table-column type="selection" width="30" align="center" />
        <el-table-column :label="$t('device.deviceSnId')" :width="300" prop="deviceSnId">
          <template #default="scope">
            <div style="display: flex; align-items: center">
              <el-icon
                v-if="
                  ((scope.row.deviceType == 'gateway' && scope.row.checkHealth == 1) ||
                    scope.row.deviceType != 'gateway') &&
                  scope.row.deviceStatus == '01'
                "
                size="32"
              >
                <WarnTriangleFilled style="margin-right: 10px; color: red" />
              </el-icon>
              {{ scope.row.deviceSnId }}
            </div>
          </template>
        </el-table-column>
        <el-table-column :label="$t('device.deviceType.title')" align="center">
          <template #default="scope">
            <el-tag v-if="scope.row.deviceType === 'gateway'" type="primary">
              {{ $t("device.deviceType.gateway") }}
            </el-tag>
            <el-tag v-else-if="scope.row.deviceType === 'node'" type="success">
              {{ $t("device.deviceType.node") }}
            </el-tag>
            <el-tag v-else-if="scope.row.deviceType === 'tag'" type="info">
              {{ $t("device.deviceType.tag") }}
            </el-tag>
            <el-tag v-else type="danger">{{ $t("common.unknown") }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column :label="$t('device.batteryStatus')" align="center">
          <template #default="scope">
            <div v-if="scope.row.deviceType == 'tag'">
              <div v-if="scope.row.batteryStatus >= 0 && scope.row.batteryStatus <= 100">
                <el-progress
                  type="circle"
                  :stroke-width="3"
                  :width="50"
                  class="custom-progress"
                  :percentage="scope.row.batteryStatus"
                  :color="scope.row.batteryStatus < 20 ? '#f56c6c' : ''"
                >
                  <template #default="{ percentage }">
                    <span class="percentage-value">{{ percentage }}%</span>
                  </template>
                </el-progress>
              </div>
              <div v-else-if="scope.row.batteryStatus >= 128">
                <e-tag type="danger">{{ $t("device.tagMiss") }}</e-tag>
              </div>
              <div v-else>
                {{ scope.row.batteryStatus }}
              </div>
            </div>
          </template>
        </el-table-column>

        <el-table-column :label="$t('device.deviceRemark')" prop="deviceRemark" min-width="100" />
        <el-table-column fixed="right" :label="$t('common.action')" width="130">
          <template #default="scope">
            <el-button
              v-if="scope.row.deviceType == 'node'"
              v-hasPerm="'device:edit'"
              type="primary"
              size="small"
              link
              icon="edit"
              @click="handleOpenDialog(scope.row.deviceId)"
            >
              {{ $t("common.edit") }}
            </el-button>
            <el-button
              v-hasPerm="'device:delete'"
              type="danger"
              size="small"
              link
              icon="delete"
              @click="handleDelete(scope.row.deviceId)"
            >
              {{ $t("common.delete") }}
            </el-button>
          </template>
        </el-table-column>
      </el-table>

      <pagination
        v-if="total > 0"
        v-model:total="total"
        v-model:page="queryParams.pageNum"
        v-model:limit="queryParams.pageSize"
        @pagination="handleQuery"
      />
    </el-card>
    <el-dialog
      v-model="dialog.visible"
      :title="dialog.title"
      :width="dialogWidth"
      @close="handleCloseDialog"
    >
      <div>
        <div id="reader" style="position: absolute; z-index: 100; display: none; width: 100%" />
        <button v-if="isScanning" @click="stopScanning">{{ $t("common.stopScanning") }}</button>
      </div>
      <el-form ref="roleFormRef" :model="formData" :rules="rules">
        <!--<el-form-item :label="$t('device.deviceType.title')" prop="deviceType">
          <el-radio-group v-model="formData.deviceType">
            <el-radio value="gateway">{{ $t("device.deviceType.gateway") }}</el-radio><el-radio value="tag">{{ $t("device.deviceType.tag") }}</el-radio>
            <el-radio value="node">{{ $t("device.deviceType.node") }}</el-radio>
          </el-radio-group>
        </el-form-item>-->
        <el-form-item :label="$t('device.deviceSnId')" prop="deviceSnId">
          <el-input
            v-model="formData.deviceSnId"
            :placeholder="$t('common.plsInput') + $t('device.deviceSnId')"
          >
            <template #suffix>
              <el-icon class="el-input__icon" type="primary">
                <Camera v-if="!isScanning" @click="startScanning" />
              </el-icon>
            </template>
          </el-input>
        </el-form-item>
        <el-form-item
          v-if="formData.deviceType == 'node'"
          :label="$t('device.deviceRemark')"
          prop="deviceRemark"
        >
          <el-input
            v-model="formData.deviceRemark"
            :placeholder="$t('common.plsInput') + $t('device.deviceRemark')"
          />
        </el-form-item>
      </el-form>

      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="handleSubmit">{{ $t("common.confirm") }}</el-button>
          <el-button @click="handleCloseDialog">{{ $t("common.cancel") }}</el-button>
        </div>
      </template>
    </el-dialog>
    <el-dialog
      v-model="gatewayDialog.visible"
      :title="gatewayDialog.title"
      :width="dialogWidth"
      @close="handleCloseGatewayDialog"
    >
      <el-form>
        <el-form-item :label="$t('bluetooth.gatewayNo')">
          <el-input v-model="gatewayNo" type="text" :readonly="true" />
        </el-form-item>
        <el-form-item :label="$t('bluetooth.remark')">
          <el-input v-model="gatewayremark" type="text" />
        </el-form-item>
        <el-form-item :label="$t('bluetooth.wifiSSID')">
          <el-select
            v-model="wifiSSID"
            :placeholder="$t('common.choose')"
            :no-match-text="$t('common.choose')"
          >
            <el-option v-for="item in wifiOptions" :key="item" :label="item" :value="item" />
          </el-select>
        </el-form-item>
        <el-form-item :label="$t('bluetooth.wifiPw')">
          <el-input
            v-model="wifiPassword"
            type="text"
            :placeholder="$t('plsInput') + t('bluetooth.wifiPw')"
          />
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="writeWifiToGateway">
            {{ $t("common.confirm") }}
          </el-button>
          <el-button @click="handleCloseGatewayDialog">{{ $t("common.cancel") }}</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import qrcodeScanSound from "@/assets/qrcodescan.mp3";
import { ref } from "vue";
import { Html5Qrcode } from "html5-qrcode";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
defineOptions({
  name: "Device",
  inheritAttrs: false,
});

import DeviceAPI, { DeviceForm, DevicePageQuery, DevicePageVO } from "@/api/device/index";
const screenWidth = window.innerWidth;
const dialogWidth = screenWidth < 768 ? "90%" : "500px";
const queryFormRef = ref(ElForm);
const roleFormRef = ref(ElForm);

const loading = ref(false);
const ids = ref<number[]>([]);
const total = ref(0);
const gatewayNo = ref<string>("");
const gatewayType = ref<number>(1);
const gatewayremark = ref<string>("");
const server = ref<any>();
const scanBluetooth = ref<boolean>(false);

const isScanning = ref<boolean>(false);
const html5QrCode = ref<Html5Qrcode | null>(null);

const wifiSSID = ref<string>("");
const wifiPassword = ref<string>("");
const wifiOptions = ref<any[]>([]);
const gatewayDialog = reactive({
  title: t("bluetooth.title"),
  visible: false,
});

const gatewayBtnTitle = ref<string>(t("bluetooth.title"));

const queryParams = reactive<DevicePageQuery>({
  pageNum: 1,
  pageSize: 10,
  keywords: "",
  deviceType: "",
});

const list = ref<DevicePageVO[]>();

const dialog = reactive({
  title: "",
  visible: false,
});

const formData = reactive<DeviceForm>({
  deviceType: "node",
});

const rules = reactive({
  deviceSnId: [
    { required: true, message: t("common.plsInput") + t("device.deviceSnId"), trigger: "blur" },
  ],
  deviceType: [
    {
      required: true,
      message: t("common.plsChoose") + t("device.deviceType.title"),
      trigger: "blur",
    },
  ],
});

const deviceTypeOptions = ref<OptionType[]>([
  {
    label: t("common.all"),
    value: "",
  },
  {
    label: t("device.deviceType.gateway"),
    value: "gateway",
  },
  {
    label: t("device.deviceType.node"),
    value: "node",
  },
  {
    label: t("device.deviceType.tag"),
    value: "tag",
  },
]);

function refreshGateway() {
  location.reload();
}

function handleQuery() {
  loading.value = true;
  DeviceAPI.getList(queryParams)
    .then((data) => {
      list.value = data.list;
      total.value = data.total;
    })
    .finally(() => {
      loading.value = false;
    });
}

function handleResetQuery() {
  queryFormRef.value.resetFields();
  queryParams.pageNum = 1;
  handleQuery();
}

function handleSelectionChange(selection: any) {
  ids.value = selection.map((item: any) => item.deviceId);
}

function handleOpenDialog(deviceId?: number) {
  dialog.visible = true;
  if (deviceId) {
    dialog.title = t("common.edit") + t("device.deviceType.node");
    loading.value = true;
    DeviceAPI.getFormData(deviceId)
      .then((data) => {
        Object.assign(formData, data);
      })
      .finally(() => {
        loading.value = false;
      });
  } else {
    dialog.title = t("common.add") + t("device.deviceType.node");
  }
}

function handleSubmit() {
  roleFormRef.value.validate((valid: any) => {
    if (valid) {
      if (formData.deviceType == "node" && !formData.deviceRemark) {
        ElMessage.error(t("common.plsInput") + t("device.deviceRemark"));
        return;
      }
      loading.value = true;
      const deviceId = formData.deviceId;
      if (deviceId) {
        DeviceAPI.update(formData)
          .then((res) => {
            if (res.data.code === 200) {
              ElMessage.success(res.data.message);
              handleCloseDialog();
              handleQuery();
            } else {
              ElMessage.error(res.data.message);
            }
          })
          .finally(() => (loading.value = false));
      } else {
        DeviceAPI.add(formData)
          .then((res) => {
            ElMessage.success(res.data.message);
            handleCloseDialog();
            handleQuery();
          })
          .finally(() => (loading.value = false));
      }
    }
  });
}

function handleCloseDialog() {
  dialog.visible = false;

  roleFormRef.value.resetFields();
  roleFormRef.value.clearValidate();

  formData.deviceId = undefined;
  formData.deviceSnId = undefined;
  formData.deviceType = "node";
  formData.deviceRemark = undefined;
  console.log(isScanning.value);

  setTimeout(() => {
    stopScanning();
  }, 100);
}

// delete
function handleDelete(deviceId?: number) {
  const deviceIds = [deviceId || ids.value].join(",");
  if (!deviceIds) {
    ElMessage.warning(t("common.plsChooseDeleteItem"));
    return;
  }

  ElMessageBox.confirm(t("common.confirmDelete"), t("common.warning"), {
    confirmButtonText: t("common.confirm"),
    cancelButtonText: t("common.cancel"),
    type: "warning",
  }).then(
    () => {
      loading.value = true;
      DeviceAPI.deleteByIds(deviceIds)
        .then((res) => {
          if (res.data.code === 200) {
            ElMessage.success(res.data.message);
            handleQuery();
          } else {
            ElMessage.error(res.data.message);
          }
        })
        .finally(() => (loading.value = false));
    },
    () => {
      ElMessage.info(t("common.cancelDelete"));
    }
  );
}

onMounted(() => {
  handleQuery();
});

const startScanning = () => {
  html5QrCode.value = new Html5Qrcode("reader");
  isScanning.value = true;

  const readerElement = document.getElementById("reader");
  if (readerElement) {
    readerElement.style.display = "block";
  }

  html5QrCode.value
    .start(
      { facingMode: "environment" },
      {
        fps: 20,
        qrbox: 250,
      },
      (decoded: string) => {
        playSound();
        formData.deviceSnId = decoded.slice(-6);
        stopScanning();
      },
      (err: any) => {
        isScanning.value = false;
      }
    )
    .catch((err: Error) => {
      isScanning.value = false;
    });
};

const stopScanning = () => {
  if (html5QrCode.value) {
    html5QrCode.value
      .stop()
      .then(() => {
        isScanning.value = false;
        html5QrCode.value = null;
        const readerElement = document.getElementById("reader");
        if (readerElement) {
          readerElement.style.display = "none";
        }
      })
      .catch((err: Error) => {});
  }
};

const playSound = () => {
  const audio = new Audio(qrcodeScanSound);
  audio.play().catch((error: Error) => {});
};

function handleCloseGatewayDialog() {
  gatewayDialog.visible = false;
  wifiSSID.value = "";
  wifiPassword.value = "";
  gatewayNo.value = "";
  gatewayType.value = 1;
  gatewayremark.value = "";
  wifiOptions.value = [];
  gatewayBtnTitle.value = t("bluetooth.title");
}

const connectAndRead = async () => {
  if (!(navigator as any).bluetooth) {
    ElMessage.error(t("bluetooth.notsupport"));
    return;
  }

  try {
    scanBluetooth.value = true;
    if (server.value?.connected) {
      server.value.disconnect();
    }

    gatewayBtnTitle.value = t("bluetooth.connecting");

    // request devices
    const device = await (navigator as any).bluetooth
      .requestDevice({
        //acceptAllDevices: true,
        //optionalServices: [0xa00a],
        filters: [
          { services: [0xa00a] }, // service UUID is 0xA00A
        ],
      })
      .then((device: any) => {
        console.log(`device name: ${device.name}`);
        console.log(`device id: ${device.id}`);
        return device;
      });

    // connect to gatt server
    server.value = await device.gatt.connect();

    gatewayNo.value = device.name.slice(-6).toUpperCase();
    if (device.name.charAt(0) === "R") {
      gatewayType.value = 0;
    }

    // get service by uuid
    const wifiService = await server.value.getPrimaryService(0xa00a);
    const wifiChar = await wifiService.getCharacteristic(0xd007);
    const wifiListValue = await wifiChar.readValue();
    const decoder = new TextDecoder("utf-8");
    const stringValue = decoder.decode(wifiListValue.buffer);
    console.log(`result：${stringValue}`);
    const wifis = stringValue.split(",");
    wifiOptions.value = [];
    const regex = /[a-zA-Z0-9\W\u4e00-\u9fff]/;
    for (let i = 0; i < wifis.length; i++) {
      if (wifis[i] == "") {
        continue;
      }
      if (!regex.test(wifis[i])) {
        continue;
      }
      wifiOptions.value.push(wifis[i]);
    }

    //get the wifi ssid have set
    const wifiReadChar = await wifiService.getCharacteristic(0xd001);
    const wifiReadNow = await wifiReadChar.readValue();
    const nowSSID = decoder.decode(wifiReadNow.buffer);
    wifiSSID.value = nowSSID;

    //get the wifi password have set
    const wifiPwReadChar = await wifiService.getCharacteristic(0xd006);
    const wifiPwNow = await wifiPwReadChar.readValue();
    const nowSSIDPw = decoder.decode(wifiPwNow.buffer);
    wifiPassword.value = nowSSIDPw;

    scanBluetooth.value = false;
    gatewayDialog.visible = true;
    gatewayBtnTitle.value = t("bluetooth.title");
  } catch (error) {
    console.error("connnect faild:", error);
    scanBluetooth.value = false;
    ElMessage.error((error as any).message);
    gatewayBtnTitle.value = t("bluetooth.title");
  }
};

async function writeWifiToGateway() {
  if (!wifiSSID.value || !wifiPassword.value) {
    ElMessage.error(t("bluetooth.ssidandpwrequired"));
    return;
  }
  if (!server.value) {
    ElMessage.error(t("bluetooth.notConnected"));
    return;
  }

  try {
    //get wifi service
    const wifiService = await server.value.getPrimaryService(0xa00a);

    //write wifi ssid
    const wifiWriteChar = await wifiService.getCharacteristic(0xd002);
    await wifiWriteChar.writeValue(new TextEncoder().encode(`ID=${wifiSSID.value.trim()}`));
    const decoder = new TextDecoder("utf-8");

    //get new wifi ssid have set
    const wifiReadChar = await wifiService.getCharacteristic(0xd001);
    const wifiReadNow = await wifiReadChar.readValue();
    const nowSSID = decoder.decode(wifiReadNow.buffer);
    console.log(`NOW SSID:${nowSSID}`);

    //write wifi password
    const wifiWritePasswdChar = await wifiService.getCharacteristic(0xd005);
    await wifiWritePasswdChar.writeValue(
      new TextEncoder().encode(`PW=${wifiPassword.value.trim()}`)
    ); //28905837

    // get new wifi password have set
    const wifiPwReadChar = await wifiService.getCharacteristic(0xd006);
    const wifiPwNow = await wifiPwReadChar.readValue();
    const nowSSIDPw = decoder.decode(wifiPwNow.buffer);
    console.log(`NOW PW: ${nowSSIDPw}`);

    if (nowSSID == wifiSSID.value && nowSSIDPw == wifiPassword.value) {
      DeviceAPI.saveGateway({
        snId: gatewayNo.value,
        gatewayType: gatewayType.value,
        remark: gatewayremark.value,
      }).then((res) => {
        if (res.data.code === 200) {
          ElMessage.success(t("bluetooth.setSuccess"));
          handleCloseGatewayDialog();
          setTimeout(() => {
            location.reload();
          }, 500);
        } else {
          ElMessage.error(res.data.message);
          gatewayBtnTitle.value = t("bluetooth.title");
        }
      });
    } else {
      ElMessage.error(t("bluetooth.setFail"));
      gatewayBtnTitle.value = t("bluetooth.title");
    }
  } catch (error) {
    ElMessage.error((error as any).message);
    gatewayBtnTitle.value = t("bluetooth.title");
  }
}
</script>

<style scoped>
.custom-progress .percentage-value {
  font-size: 14px;
  font-weight: bold;
  color: #000;
}
</style>
